#pragma once
#include <list>
#include "Pattern\IDataHandler.h"
#include "Com\SerialPort.h"
using namespace std;

enum TalkState {
	cameraTalk_0 = 0,
	cameraTalk_1 = 1,
	cameraTalk_2 = 2,
	cameraTalk_3 = 3,
	cameraTalk_4 = 4,
	cameraTalk_5 = 5,
	noCameraTalk = 6,
};

typedef struct LastComData {
	UINT8 dest;
	UINT8 cmd;
	UINT8 parm1;
	UINT8 parm2;
	bool mReply;
}LastComData;

typedef struct ComDataPacket 
{
	UINT8 data[20];
	UINT8 length;
	bool isUsed;
	uint8_t portnr;
}ComDataPacket;

typedef struct ComDataQueue
{
	ComDataPacket packet;
	uint8_t SN;
	ComDataQueue *next;
}ComDataQueue;

class CRouter : public IDataHandler
{
private:
	CRouter();
public:
	static CRouter* GetInstance() {
		static CRouter instance;
		return &instance;
	}
	~CRouter();

public:
	virtual void HandleData(UINT8* pRxData, size_t length, UINT8 portnr);

	void    RegisterHandler(IDataHandler* pHandler,  UINT8 whatCmd);

	void    SendData(UINT8* pData, size_t length);

	/*void    AttachSender(CSerialPort* pSender);*/

	uint32_t CRC32Software(uint8_t *pData, uint16_t Length);
	bool CheckCRC32(uint8_t *pData, uint16_t Length);

	bool InitRouter();
	bool StartThread();
private:	
	CSerialPort* mComPort[6];

	uint8_t comArray[13][17];

    CSerialPort*    mSender;
	IDataHandler*   mHandleres[10];

	ComDataPacket   mTxCache[10];
	ComDataPacket   mRxCache[10];

	CRITICAL_SECTION mCSSend;
	CRITICAL_SECTION mCSReceive;
	CRITICAL_SECTION mCSReOneCmd;
	CRITICAL_SECTION mCSHandle;
	CRITICAL_SECTION mCSVolume;

	CWinThread *mRouterThread;
	static UINT RouterThread(LPVOID pParam);
	bool mIsThreadAlive;

	HANDLE mEndThreadEvent;
	HANDLE mSendEvent;
	HANDLE mReceiveEvent;
	HANDLE mEventArrayRouter[3];

	std::list<ComDataPacket*> mComDataRxList;
	std::list<ComDataPacket*> mComDataTxList;

	void AddRxList(ComDataPacket* p);
	void RemoveRxList(list<ComDataPacket*>::iterator iter);

	void AddTxList(ComDataPacket* p);
	void RemoveTxList(list<ComDataPacket*>::iterator iter);
private:
	HANDLE mENDThread;
	HANDLE mSetVolume;
	HANDLE mReSetVolume;
	HANDLE mHostTalk;
	HANDLE mReHostTalk;
	HANDLE mCameraTalk;
	HANDLE mReCameraTalk;
	HANDLE mStopTalk;
	HANDLE mReStopTalk;
	HANDLE mCameraWantTalk;
	HANDLE mCameraCanTalk;
	HANDLE mReCameraCanTalk;
	HANDLE mAlarmStart;
	HANDLE mReAlarmStart;
	HANDLE mAlarmStop;
	HANDLE mReAlarmStop;
	HANDLE mLEDChange;
	HANDLE mReOneCmd;

	HANDLE mEventArray[18];

	uint8_t mHandleArray[6];

	CWinThread *mComServeThread;

	ComDataQueue mComDataQueue[6][6];

	uint8_t mReplyFlg[2][6];

	ComDataQueue *mSendData[6];
	ComDataQueue *mSetSendData[6];

	LastComData mLastComData[6];
	LastComData mReComData[6];

	uint8_t mOldMac[6][6];
	uint8_t mNewMac[6][6];

	uint8_t mPortCmd[3];
	static UINT ComServeThread(LPVOID pParam);
	void LoadComArray();

	uint8_t mPostMsg[5][17];

	uint8_t mVolume;
	uint8_t mWhichPort[5];

	TalkState mTalkState;
public:
	uint8_t * GetHandle();
	void SetVolume(uint8_t volume);
	void HostTalk();
	void CameraTalk();
	void StopTalk();
	void CameraCanTalk(bool can);
	void Alarm();


	void SetCameraHandle(uint8_t *p);
	void SetTalkHandle(uint8_t *p);

	void AfterSend(uint8_t com);

	void InitServeThread();

	void SetServeEvent();

	inline bool CheckNewCamera(uint8_t *newMac, uint8_t *oldMac);

	uint8_t FindPort(uint8_t *p);

	void LEDSet();

};